package com.yixun.qfbao.api.service.login;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.yixun.qfbao.api.service.CompanyRelationService;
import com.yixun.qfbao.api.service.PersonnelService;
import com.yixun.qfbao.apidto.RegistReqDto;
import com.yixun.qfbao.mapper.CompanyMapper;
import com.yixun.qfbao.mapper.DepartmentMapper;
import com.yixun.qfbao.model.Company;
import com.yixun.qfbao.model.CompanyRelation;
import com.yixun.qfbao.model.Department;
import com.yixun.qfbao.model.dto.CompanyDto;
import com.yixun.qfbao.model.dto.CompanyRelationDto;
import com.yixun.qfbao.model.dto.DepartmentDto;
import com.yixun.qfbao.model.dto.PartnerInfoDto;
import com.yixun.qfbao.model.enums.DelFlagEnum;
import com.yixun.qfbao.service.PartnerInfoService;
import com.yixun.qfbao.service.ValidateCodeService;
import com.yixun.qfbao.util.PasswordUtil;
import com.yixun.qfbao.util.RedisUtil;

/**
 * @author zilong.liu
 * @date 2020-7-31
 * @desc
 *		目前不知道其他的登录是否和小程序一致，暂时把分销小程序拆分的方法当作父类的默认方法
 *		后续有需要的话可以再进行拆分，直接把当前类的方法拷贝到分销小程序即可。然后把公共的默认方法放到当前父类
 */
@Service
public class BaseLoginService {
	
	@Autowired
	ValidateCodeService validateCodeService;
	
	@Autowired
	PartnerInfoService partnerInfoService;
	
	@Autowired
	DepartmentMapper departmentMapper;
	
	@Autowired
	PersonnelService personnelService;
	
	@Autowired
	CompanyMapper companyMapper;
	
	@Autowired
	CompanyRelationService companyRelationService;
	
	private static final Logger LOGGER = LoggerFactory.getLogger(BaseLoginService.class);
	
	protected int[] validTime = new int[] {0, 1, 2, 3, 3};
	/**
	 * 	发送验证码
	 * 	统一定义返回值规则
	 * @param phone
	 * @param type
	 * @param companyUuid
	 * @return
	 */
	public String sendVerificationCode(String phone, String type, Long companyId, 
			int companyType, String loginType, List<String> companyUuids) {
		//判断是否已经发送
		if(RedisUtil.get(phone + "-" + loginType + "-" + type, String.class) != null) {
			return "验证码已经下发，请不要重复发送";
		}
		
		boolean filterCheckFailStatus = false;
		if("3".equals(type)) {
			CompanyRelationDto companyRelationDto = new CompanyRelationDto();
			companyRelationDto.setAgentCompany(companyId);
			List<CompanyRelation> companyRelations = companyRelationService.selectListByDto(companyRelationDto);
			if(companyRelations == null || companyRelations.size() == 0) {
				return "当前公司无对应的总代公司，请确认";
			}
			companyId = companyRelations.get(0).getDevCompany();
			filterCheckFailStatus = true;
		}else if("4".equals(type)) {
			Company company = companyMapper.selectById(companyId);
			if(company == null) {
				return "当前公司邀请码有误";
			}filterCheckFailStatus = true;
		}
		
		Map<String, Object> partnerInfo = getPartnerInfoByPhone(phone, companyId, "", companyType, companyUuids, filterCheckFailStatus);
		
		//查找手机号所属的可用的公司ID
		//判断公司是否存在
		if("3".equals(type) || "4".equals(type)) {
			if(partnerInfo != null){
				return "账号已存在";
			}
			CompanyDto companyDto = new CompanyDto();
			if(companyId == null) {
				return "当前公司码不存在，请确认";
			}
			companyDto.setId(companyId);
			companyDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
			if(companyMapper.selectByDto(companyDto) == null) {
				return "当前公司不存在，请确认";
			}
		}else {
			if(partnerInfo == null){
				return "未查询到对应的账号";
			}
			companyId = Long.parseLong(String.valueOf(partnerInfo.get("companyId")));
		}
		LOGGER.info("本次" + phone + "对应的登录公司ID为：" + companyId);
		Map<String, Object> sendParams = packSendParams(type);
		//发送短信
		String messageContent = String.valueOf(sendParams.get("messageContent"));
		String msgId = String.valueOf(sendParams.get("msgId"));
		String smsDesc = String.valueOf(sendParams.get("smsDesc"));
		String systemId = String.valueOf(sendParams.get("systemId"));
		String code = String.valueOf(sendParams.get("code"));
		String[] msgs = (String[])sendParams.get("msgs");
		boolean sendResult = validateCodeService.sendAndSaveSmsmsg(phone, messageContent, msgId, smsDesc, 
				systemId, "", code, companyId, msgs);
		
		//统一设置redis的key为  号码-系统标识-类型    7代表分销 1代表
		if(sendResult) {
			String key = phone + "-" + systemId + "-" + type;
			RedisUtil.set(key, code);
			RedisUtil.expire(key, validTime[Integer.parseInt(type)], TimeUnit.MINUTES);
		}
		return sendResult? "发送成功": "发送失败";
	}




	/**
	 * 组装参数，各子类必须重写
	 * @return
	 */
	protected Map<String, Object> packSendParams(String type){
		return null;
	}
	
	/**
	 *      根据用户手机账号权限
	 * @param phone
	 * @param checkStatus 如果为true 则只返回审核状态为-1的
	 * @return
	 */
	protected Map<String, Object> getPartnerInfoByPhone(String phone, Long companyId, String pwd,
			int companyType, List<String> companyUuids, boolean filterCheckFailStatus) {
		Map<String, Object> phoneAndCompanyInfo = new HashMap<>();
		phoneAndCompanyInfo.put("phone", phone);
		phoneAndCompanyInfo.put("pwd", pwd);
		phoneAndCompanyInfo.put("companyType", companyType);
		if(filterCheckFailStatus) {
			phoneAndCompanyInfo.put("filterCheckFailStatus", filterCheckFailStatus);
		}
		//查询当前手机号在对应的公司中是否有对应的partner信息
		List<Map<String, Object>> partnerInfos = 
				partnerInfoService.getAllPartnerInfoByPhoneAndCompany(phoneAndCompanyInfo);
		if(partnerInfos == null || partnerInfos.isEmpty()) {
			return null;
		}
		//根据当前员工的公司ID，筛选不是当前总代下的数据
		if(companyId != null && companyId != 0L) {
			for (int i = partnerInfos.size() - 1; i >= 0; i--) {
				Map<String, Object> partnerInfo = partnerInfos.get(i);
				Long partnerCompanyId = Long.parseLong(String.valueOf(partnerInfo.get("companyId")));
				if(companyId.longValue() != partnerCompanyId.longValue()) {
					partnerInfos.remove(partnerInfo);
				}
			}
		}
		//  如果需要登录到对应的公司上，则查询当前伙伴的代理公司是否在集合中
		if(companyUuids != null && companyUuids.size() != 0) {
			for (int i = partnerInfos.size() - 1; i >= 0; i--) {
				Map<String, Object> partnerInfo = partnerInfos.get(i);
				String companyUuid = String.valueOf(partnerInfo.get("companyUuid"));
				if(!companyUuids.contains(companyUuid)) {
					partnerInfos.remove(partnerInfo);
				}
			}
		}
//		Date date = new Date();
		if(partnerInfos == null || partnerInfos.isEmpty()) {
			return null;
		}
		Map<String, Object> retPartnerInfo = partnerInfos.get(0);
		//查找到最晚创建的账号时间，用于后续短信记录
		for (int i = 0, j = partnerInfos.size(); i < j; i ++) {
			if(i == 0) {
				continue;
			}else {
				Date maxCreateTime = (Date) retPartnerInfo.get("createTime");
				Date curCreateTime = (Date) partnerInfos.get(i).get("createTime");
				if(maxCreateTime.before(curCreateTime)) {
					retPartnerInfo = partnerInfos.get(i);
				}
			}
		}
		return retPartnerInfo;
	}
	
	/**
	 *      根据用户手机账号权限
	 * @param phone
	 * @return
	 */
	public List<Map<String, Object>> getPartnerInfosByPhone(String phone, Long companyId, String pwd,
			int companyType, List<String> companyUuids) {
		Map<String, Object> phoneAndCompanyInfo = new HashMap<>();
		phoneAndCompanyInfo.put("phone", phone);
		phoneAndCompanyInfo.put("companyType", companyType);
		//查询当前手机号在对应的公司中是否有对应的partner信息
		List<Map<String, Object>> partnerInfos = 
				partnerInfoService.getAllPartnerInfoByPhoneAndCompany(phoneAndCompanyInfo);
		if(partnerInfos == null || partnerInfos.isEmpty()) {
			return null;
		}
		//根据当前员工的公司ID，筛选不是当前总代下的数据
		if(companyId != null && companyId != 0L) {
			for (int i = partnerInfos.size() - 1; i >= 0; i--) {
				Map<String, Object> partnerInfo = partnerInfos.get(i);
				Long partnerCompanyId = Long.parseLong(String.valueOf(partnerInfo.get("companyId")));
				if(companyId.longValue() != partnerCompanyId.longValue()) {
					partnerInfos.remove(partnerInfo);
				}
			}
		}
		//  如果需要登录到对应的公司上，则查询当前伙伴的代理公司是否在集合中
		if(companyUuids != null && companyUuids.size() != 0) {
			for (int i = partnerInfos.size() - 1; i >= 0; i--) {
				Map<String, Object> partnerInfo = partnerInfos.get(i);
				String companyUuid = String.valueOf(partnerInfo.get("companyUuid"));
				if(!companyUuids.contains(companyUuid)) {
					partnerInfos.remove(partnerInfo);
				}
			}
		}
		// 判断是否有密码一直的。如果没有一个密码一致，则不给登录
		if(StringUtils.isNotEmpty(pwd)) {
			boolean loginFlag = false;
			for (int i = partnerInfos.size() - 1; i >= 0; i--) {
				Map<String, Object> partnerInfo = partnerInfos.get(i);
				String password = String.valueOf(partnerInfo.get("password"));
				if(pwd.equals(password)) {
					loginFlag = true; 
					break;
				}
			}
			if(!loginFlag) return null;
		}
		return partnerInfos;
	}
	
	/**
	 *  根据公司ID获取门户和组别信息，并组装
	 * @param companyId
	 */
	public List<Map<String, Object>> getOrgAndGroupByCompanyUuid(Long companyId, Long storeId, Long groupId) {
		DepartmentDto departmentDto = new DepartmentDto();
		departmentDto.setMerchantId(companyId);
		departmentDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		List<Department> departments = departmentMapper.selectListByDto(departmentDto);
		List<Map<String, Object>> storeList = new ArrayList<>();
		
		if(departments == null || departments.size() == 0) {
			return null;
		}
		
		//先分类门店以及小组
		Long departmentId = 0L;
		for (Department department : departments) {
			if(department.getParentId() == 0) {
				departmentId = department.getId();
			}
		}
		Map<String, Object> lastMap = new HashMap<>();
		for (Department department : departments) {
			if(department.getId().longValue() == storeId.longValue()) {
				lastMap.put("storeName", department.getDepartmentName());
			}
			if(department.getId().longValue() == groupId.longValue()) {
				lastMap.put("groupName", department.getDepartmentName());
			}
			if(department.getParentId().longValue() == departmentId.longValue()) {
				Map<String, Object> store = new HashMap<>();
				List<Department> groupList = new ArrayList<>();
				store.put("storeInfo", department);
				store.put("groupList", groupList);
				for (Department group : departments) {
					if(group.getParentId().longValue() == department.getId().longValue()) {
						groupList.add(group);
					}
				}
				storeList.add(store);
			}
		}
		storeList.add(lastMap);
		return storeList;
	}
	
	/**
	 *   重置密码
	 *   1、校验验证码
	 *   2、更新数据库密码，需要按照查询到员工的规则获取员工ID
	 *   3、删除验证码，让其失效
	 * @param phone
	 * @param pwd
	 * @param verificationCode
	 * @return
	 */
	public String resetPwd(String phone, String pwd, String verificationCode, String loginType) {
		
		//校验验证码
		if(!validateCode(2, phone, loginType, verificationCode)) {
			return "验证码有误或已过期";
		}
		
		//获取员工Id
		Map<String, Object> partnerInfo = getPartnerInfoByPhone(phone, 0L, "", 1, null, false);
		if(partnerInfo == null){
			return "未查询到对应的账号";
		}
		Long partnerId = Long.parseLong(String.valueOf(partnerInfo.get("partnerId")));
		
		//重置密码
		PartnerInfoDto editInfo = new PartnerInfoDto();
        editInfo.setId(partnerId);
        editInfo.setPassword(PasswordUtil.md5Hex(pwd));
        partnerInfoService.update(editInfo);
		
        //移除验证码令其失效
        RedisUtil.delete(phone + "-" + loginType + "-" + 2);
		return "成功";
	}
	
	/**
	 * 校验短信验证码
	 * @param type 1、登录 2、忘记密码 3、注册
	 * @param verificationCode
	 * @return
	 */
	public boolean validateCode(int type, String phone, String loginType, String verificationCode) {
		String key = phone + "-" + loginType + "-" + type;
		String code = RedisUtil.get(key, String.class);
		LOGGER.info("本次验证码查询key为:" + key);
		if(StringUtils.isNotBlank(verificationCode) && verificationCode.equals(code)) {
			return true;
		}
		return false;
	}
	
	/**
	 * 用户注册
	 * 1、校验短信验证码
	 * 2、调用原先注册逻辑进行注册
	 * @return
	 * @throws Exception 
	 */
	public String regist(String accountName, String companyCode, String groupId, String storeId, String phone,
			String verificationCode, String pwd, String loginType, Long qrcodeOriginPartnerId) throws Exception {
		if(!validateCode(3, phone, loginType, verificationCode)) {
			return "验证码无效";
		}
		RegistReqDto registReqDto = new RegistReqDto();
		registReqDto.setAccountName(accountName);
		registReqDto.setCompanyCode(companyCode);
		registReqDto.setLoginType(loginType);
		registReqDto.setPhone(phone);
		registReqDto.setRegisterPwd(pwd);
		registReqDto.setZubie(groupId);
		registReqDto.setMendian(storeId);
		registReqDto.setQrcodeOriginPartnerId(qrcodeOriginPartnerId);
		return personnelService.regist(registReqDto).getResultMsg();
	}
	
	/**
	 *  登录
	 * @param phone
	 * @param verificationCode
	 * @param pwd
	 * @param loginWay 1验证码  2密码
	 * @param loginType 
	 * @return
	 * 		1、如果是验证码登录，则验证验证码
	 * 		2、查找到对应的partner
	 * 		3、将partner信息存入登录的redis中（登录过滤器目前有bug）
	 * 		
	 */
	public Map<String, Object> login(String phone, String verificationCode, String pwd, 
			int loginWay, String loginType, String openId, List<String> companyUuids) {
		Map<String, Object> resMap = new HashMap<>();
		String realPwd = PasswordUtil.md5Hex(pwd);
		//如果是验证码登录，则先校验验证码是否正确
		if(loginWay == 1) {
			if(!validateCode(1, phone, loginType, verificationCode)) {
				resMap.put("msg", "验证码错误");
				return resMap;
			}
			realPwd = "";
		}
		
		//获取partnerinfo信息，并判断
		Map<String, Object> partnerInfo = getPartnerInfoByPhone(phone, 0L, realPwd, 1, companyUuids, false);
		if(partnerInfo == null) {
			if(loginWay == 1) {
				resMap.put("msg", "账号或验证码错误，请确认后重新输入");
				return resMap;
			}else {
				resMap.put("msg", "账号或密码错误，请确认后重新输入");
				return resMap;
			}
		}
		
		resMap.put("msg", "成功");
		resMap.put("partnerInfo", partnerInfo);
		return resMap;
	}
	
	/**
	 *  登录
	 * @param phone
	 * @param verificationCode
	 * @param pwd
	 * @param loginWay 1验证码  2密码
	 * @param loginType 
	 * @return
	 * 		1、如果是验证码登录，则验证验证码
	 * 		2、查找到对应的partner
	 * 		3、将partner信息存入登录的redis中
	 * 		
	 */
	public Map<String, Object> newLogin(String phone, String verificationCode, String pwd, 
			int loginWay, String loginType, String openId, List<String> companyUuids) {
		Map<String, Object> resMap = new HashMap<>();
		String realPwd = PasswordUtil.md5Hex(pwd);
		//如果是验证码登录，则先校验验证码是否正确
		if(loginWay == 1) {
			if(!validateCode(1, phone, loginType, verificationCode)) {
				resMap.put("msg", "验证码错误");
				return resMap;
			}
			realPwd = "";
		}
		
		// 获取可以登录的公司集合
		companyUuids = getAllCompanyUuid(companyUuids, loginType);
		
		//获取partnerinfo信息，并判断
		List<Map<String, Object>> partnerInfos = getPartnerInfosByPhone(phone, 0L, realPwd, 1, companyUuids);
		
		if(partnerInfos == null) {
			if(loginWay == 1) {
				resMap.put("msg", "账号或验证码错误，请确认后重新输入");
				return resMap;
			}else {
				resMap.put("msg", "账号或密码错误，请确认后重新输入");
				return resMap;
			}
		}
		
		resMap.put("msg", "成功");
		resMap.put("partnerInfos", partnerInfos);
		return resMap;
	}
	
	/**
	 * 获取所有允许登录的companyUuid
	 * @param companyUuids
	 * @return
	 */
	public List<String> getAllCompanyUuid (List<String> companyUuids, String loginType){
		return companyUuids;
	}
	
	/**
	 * 更新openId信息。需要各子类重写
	 * 分校小程序中此方法返回的是分销小程序对应的公众号的wxopenId，此微信openId会影响后续值首页刷新时，更新openId的结果。返回时请注意
	 */
	public String updateOpenIdInfo(JSONObject wxBindInfoJson, String partnrtId, String devCompanyUuid, String enableWeappMsg) {
		return null;
	}

	public static void main(String[] args) {
		System.out.println(PasswordUtil.md5Hex("12345678"));
	}
	
}
